﻿//TODO: DEINTERLACE: Autorepositioning is not implemented yet

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Reflection;
using System.Windows.Forms;

namespace LowLevelGraphics.Filter
{
    public enum DEINTERLACE
    {
        VERTICAL,
        HORIZONTAL,
        AUTO_REPOSITIONING,
        INTERPOLATE,
        REPOSITIONING
    }

    //TODO: add parameter to be able to decide if odds or even lines should be removed

    /// <summary>
    /// Deinterlaces a given bitmap
    /// Interpolate: Calculates the environment average Color value
    /// Horizontal: Removes lines
    /// 
    /// Autorepositioning: 
    /// Tries to recalculate the position of the shifted lines
    /// odd -> shifted until it matches to even
    /// 
    /// Repositioning:
    /// Repositions the given lines. The shift is given in the constructor.
    /// 
    /// </summary>
    public class Deinterlace : BaseImageFilter
    {
        protected DEINTERLACE M_DEINTERLACE = DEINTERLACE.INTERPOLATE;
        protected int m_nPixelHorizontalShift = 1;

        protected UnsafeBitmap m_BitmapEven = null;
        protected UnsafeBitmap m_BitmapOdd = null;

        /// <summary>
        /// Initializes a new instance of the <see cref="Deinterlace"/> class.
        /// </summary>
        public Deinterlace()
            : this(DEINTERLACE.HORIZONTAL, 0)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Deinterlace"/> class.
        /// </summary>
        /// <param name="_DEINTERLACE">The _ DEINTERLACE.</param>
        public Deinterlace(DEINTERLACE _DEINTERLACE)
            : this(_DEINTERLACE, 0)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Deinterlace"/> class.
        /// </summary>
        /// <param name="_DEINTERLACE">The _ DEINTERLACE.</param>
        /// <param name="nPixelHorizontal">The n pixel horizontal.</param>
        public Deinterlace(DEINTERLACE _DEINTERLACE, int nPixelHorizontal)
        {
            M_DEINTERLACE = _DEINTERLACE;
            m_nPixelHorizontalShift = nPixelHorizontal;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Deinterlace"/> class.
        /// </summary>
        /// <param name="_deinterlace">The _deinterlace.</param>
        internal Deinterlace(Deinterlace _deinterlace)
        {
            this.M_DEINTERLACE = _deinterlace.M_DEINTERLACE;
        }

        /// <summary>
        /// Get even bitmap
        /// </summary>
        public UnsafeBitmap BitmapEven
        {
            get { return m_BitmapEven; }
        }

        /// <summary>
        /// Get ddd bitmap
        /// </summary>
        public UnsafeBitmap BitmapOdd
        {
            get { return m_BitmapOdd; }
        }

        /// <summary>
        /// Gets or sets the deinterlace mode.
        /// </summary>
        /// <value>The deinterlace mode.</value>
        public DEINTERLACE DeinterlaceMode
        {
            get { return M_DEINTERLACE; }
            set { M_DEINTERLACE = value; }
        }

        /// <summary>
        /// Execute this Filter
        /// A Debug Statement is written if a concrete Filter is called
        /// </summary>
        /// <param name="_bitmap"></param>
        /// <returns></returns>
        public override UnsafeBitmap Execute(UnsafeBitmap _bitmap)
        {
            UnsafeBitmap bitmap = _bitmap;
            UnsafeBitmap bitmapOdd = (UnsafeBitmap)_bitmap.Clone();
            List<Color> aColor = new List<Color>();
            List<Color> aColorOdd = new List<Color>();
            Color[] aColorEnvironment = new Color[8];
            List<Point> aPoint = new List<Point>(){
                new Point(-1,-1), 
                new Point(-1,0),
                new Point(-1,1),
                new Point(0,1),
                new Point(1,0),
                new Point(1,-1),
                new Point(1,1),
                new Point(0,-1)
            };

            if (M_DEINTERLACE == DEINTERLACE.AUTO_REPOSITIONING)
            {
                M_DEINTERLACE = DEINTERLACE.REPOSITIONING;
            }

            int nHeight = bitmap.Height;
            int nWidth = bitmap.Width;

            int nOffset = (int)m_fOffset;
            int y = 0;
            int x = 0;
            int yOdd = 0;

            for (y = nOffset; y < nHeight - nOffset; y++)
            {
                int nValue = (y + nOffset) % 2;
                yOdd = y > 0 ? y - 1 : y;
                if (nValue == 0)
                {
                    aColor.Clear();
                    aColorOdd.Clear();
                }
                for (x = 0; x < nWidth; x++)
                {
                    switch (M_DEINTERLACE)
                    {
                        case DEINTERLACE.HORIZONTAL:
                            if (nValue == 0)
                            {
                                aColorOdd.Add(bitmap.GetPixel(x, yOdd));
                                aColor.Add(bitmap.GetPixel(x, y));
                            }
                            else
                            {
                                bitmapOdd.SetPixel(x, yOdd, aColorOdd[x]);
                                bitmap.SetPixel(x, y, aColor[x]);
                            }
                            break;

                        case DEINTERLACE.INTERPOLATE:
                            if (nValue == 0)
                            {
                                Color colorOdd = ColorFunctions.AverageColor(Segmentation.GetEnvironmentPixelColorArray(bitmap, x, y - 1, aPoint, aColorEnvironment));
                                Color color = ColorFunctions.AverageColor(Segmentation.GetEnvironmentPixelColorArray(bitmap, x, y, aPoint, aColorEnvironment));
                                bitmapOdd.SetPixel(x, yOdd, colorOdd);
                                bitmap.SetPixel(x, y, color);
                            }
                            break;

                        case DEINTERLACE.REPOSITIONING:
                            if (nValue == 0)
                            {
                                aColor.Add(bitmap.GetPixel(x, y));
                            }
                            else
                            {
                                int nIndex = x + m_nPixelHorizontalShift;
                                if (nIndex > aColor.Count - 1)
                                {
                                    nIndex = nIndex % (aColor.Count - 1);
                                }
                                else if (nIndex < 0)
                                {
                                    nIndex = aColor.Count - 1 - nIndex;
                                }
                                bitmap.SetPixel(x, y, aColor[nIndex]);
                            }
                            break;
                    }
                }
            }

            m_BitmapOdd = bitmapOdd;
            m_BitmapEven = bitmap;
            return bitmap;
        }

        /// <summary>
        /// This is used to clone a filter, each filter must implement it's own clone functionality
        /// </summary>
        /// <returns></returns>
        public override object Clone()
        {
            return new Deinterlace(this);
        }
    }
}
